// ... existing code ...
const { Readable, Writable } = require('node:stream');
const fs = require('node:fs').promises;
const path = require('node:path');

// 检查文件读权限
async function checkReadPermission(filePath) {
  try {
    await fs.access(filePath, fs.constants.R_OK);
    console.log('文件有读权限');
    return true;
  } catch (err) {
    console.error('文件没有读权限:', err);
    return false;
  }
}

// 检查目录写权限
async function checkWritePermission(dirPath) {
  try {
    await fs.access(dirPath, fs.constants.W_OK);
    console.log('目录有写权限');
    return true;
  } catch (err) {
    console.error('目录没有写权限:', err);
    return false;
  }
}

class MyReadable extends Readable {
  constructor(filename, options) {
    super(options);
    this.filename = filename;
    this.fd = null;
    this.buffer = Buffer.alloc(1024);
    this.position = 0;
    this.open();
  }

  async open() {
    console.log('Readable打开文件:', this.filename);
    try {
      const hasReadPermission = await checkReadPermission(this.filename);
      if (!hasReadPermission) {
        this.emit('error', new Error('文件没有读权限'));
        return;
      }
      this.fd = await fs.open(this.filename, 'r');
      console.log('文件已打开，文件描述符:', this.fd);
      this.emit('open');
      this.read();
    } catch (err) {
      this.emit('error', err);
    }
  }

  async read() {
    console.log('读取文件:', this.position);
    if (!this.fd) return;
    try {
      const { bytesRead, buffer } = await this.fd.read(this.buffer, 0, this.buffer.length, this.position);
      if (bytesRead === 0) {
        await this.fd.close();
        this.push(null);
        return;
      }
      this.position += bytesRead;
      this.push(buffer.slice(0, bytesRead));
    } catch (err) {
      this.emit('error', err);
    }
  }

  _read(size) {
    console.log('_read');
    this.read();
  }
}

class MyWritable extends Writable {
  constructor(filename, options) {
    super(options);
    this.filename = filename;
    this.fd = null;
    this.open();
  }

  async open() {
    console.log('Writable打开文件:', this.filename);
    try {
      const dirPath = path.dirname(this.filename);
      const hasWritePermission = await checkWritePermission(dirPath);
      if (!hasWritePermission) {
        this.emit('error', new Error('目录没有写权限'));
        return;
      }
      this.fd = await fs.open(this.filename, 'w');
      console.log('文件已打开，文件描述符:', this.fd);
      this.emit('open');
    } catch (err) {
      this.emit('error', err);
    }
  }

  async _write(chunk, encoding, callback) {
    console.log('_write:', chunk, encoding);
    try {
      if (!this.fd) {
        await new Promise(resolve => this.once('open', resolve));
      }
      await this.fd.write(chunk);
      callback();
    } catch (err) {
      callback(err);
    }
  }

  async _final(callback) {
    try {
      if (!this.fd) {
        await new Promise(resolve => this.once('open', resolve));
      }
      await this.fd.close();
      callback();
    } catch (err) {
      callback(err);
    }
  }
}


// 检查文件和目录权限
(async () => {
  const inputFilePath = __dirname + '/input.txt';
  const outputFilePath = __dirname + '/output.txt';

  const hasReadPermission = await checkReadPermission(inputFilePath);
  const hasWritePermission = await checkWritePermission(path.dirname(outputFilePath));

  console.log(hasReadPermission, hasWritePermission)
  if (hasReadPermission && hasWritePermission) {
    // 创建自定义的 Readable 和 Writable 流实例
    const myReadable = new MyReadable(inputFilePath);
    const myWritable = new MyWritable(outputFilePath);

    // 将 Readable 流通过管道传递给 Writable 流
    myReadable.pipe(myWritable);

    // 监听错误事件
    myReadable.on('error', (err) => {
      console.error('读取文件时出错:', err);
    });

    myWritable.on('error', (err) => {
      console.error('写入文件时出错:', err);
    });

    myWritable.on('finish', () => {
      console.log('文件传输完成');
    });

    // 添加日志以调试
    myReadable.on('open', () => {
      console.log('Readable 流已打开');
    });

    myWritable.on('open', () => {
      console.log('Writable 流已打开');
    });

    myReadable.on('data', (chunk) => {
      console.log(`Received chunk: ${chunk.length} bytes`);
    });

    myWritable.on('drain', () => {
      console.log('Writable 流已清空');
    });
  }
})();